#include "HierarchyTreeModel.h"
#include "Node.h"
#include "Editor.h"
#include <QGraphicsItem>
#include <QMimeData>


HierarchyTreeModel::HierarchyTreeModel(Node* root) : root(root), markDropMimeDataRemove(false){
}
HierarchyTreeModel::~HierarchyTreeModel(){
}

QVariant HierarchyTreeModel::data(const QModelIndex &index, int role) const {
	if (!index.isValid()) return QVariant();
	if (role != Qt::DisplayRole) return QVariant();

	Node* item = static_cast<Node*>(index.internalPointer());
	return QVariant(item->name);
}
Qt::ItemFlags HierarchyTreeModel::flags(const QModelIndex &index) const {
	if (!index.isValid())
		return Qt::ItemIsDropEnabled | Qt::ItemIsEnabled;
	Qt::ItemFlags ret = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
	if (static_cast<Node*>(index.internalPointer())->type() == Node::NLayer)
		ret |=  Qt::ItemIsDropEnabled;
	return ret;
}
QVariant HierarchyTreeModel::headerData(int section, Qt::Orientation orientation,int role) const {
	if (role == Qt::DisplayRole)
		return "Object";
	return QVariant();
}
QModelIndex HierarchyTreeModel::index(int row, int column, const QModelIndex &parent) const {
	if (!hasIndex(row, column, parent))
        return QModelIndex();
	
	Node* parentItem;
	
	if (!parent.isValid())
		parentItem = root;
	else
		parentItem = static_cast<Node*>(parent.internalPointer());

	Node* childItem = parentItem->child(row);

	if (childItem)
		return createIndex(row, column, childItem);
	else
		return QModelIndex();
}
QModelIndex HierarchyTreeModel::parent(const QModelIndex &index) const {
	if (!index.isValid())
		return QModelIndex();
	Node *childItem = static_cast<Node*>(index.internalPointer());
	Node *parentItem = childItem->parent();
	if (parentItem == root || parentItem == 0) return QModelIndex();
	return createIndex(parentItem->row(), 0, parentItem);
}
int HierarchyTreeModel::rowCount(const QModelIndex &parent) const {
	Node* parentItem;
	if (!parent.isValid())
		parentItem = root;
	else
		parentItem = static_cast<Node*>(parent.internalPointer());
	return parentItem->childCount();
}
int HierarchyTreeModel::columnCount(const QModelIndex &parent) const {
	return 1;
}


void HierarchyTreeModel::addNode(Node* node, int row, const QModelIndex &parent) {
	if (row == -1) row = root->childCount();
	beginInsertRows(parent, row, row);
	if (!parent.isValid())
		root->addChildAt(node, row);
	else
		static_cast<Node*>(parent.internalPointer())->addChildAt(node, row);
	endInsertRows();
}

void HierarchyTreeModel::removeNode(Node* node) {
	removeRow(node->row(), parent(createIndex(node->row(), 0, node)));
}

void HierarchyTreeModel::setCurrentNode(Node* node) {
	if (node == 0)
		Editor::ins().getUI().hierarchyTree->setCurrentIndex(QModelIndex());
	else
		Editor::ins().getUI().hierarchyTree->setCurrentIndex(createIndex(node->row(), 0, node));
}

void HierarchyTreeModel::updateNode(Node* node) {
	QModelIndex idx = createIndex(node->row(), 0, node);
	emit dataChanged(idx, idx);
}

QMimeData* HierarchyTreeModel::mimeData(const QModelIndexList &indexes) const {
	QMimeData* mimeData = new QMimeData();
	QByteArray ba;
	void* p = indexes.front().internalPointer();
	ba.append((char*)&p, sizeof(void*));//TODO support multiple
	mimeData->setData(mimeTypes().front(), ba);
	return mimeData;
}

bool HierarchyTreeModel::removeRow(int row, const QModelIndex &parent) {
	return removeRows(row, 1, parent);
}

//do not cleanup
bool HierarchyTreeModel::removeRows(int row, int count, const QModelIndex &parent) {
	if (count != 1) return false;//TODO support multiple rows
	
	bool ret = false;
	if (markDropMimeDataRemove) {
		markDropMimeDataRemove = false;
		//already remove
		ret = true;
	} else {
		beginRemoveRows(parent, row, row + count - 1);
		Node* parentNode = parent.isValid() ? static_cast<Node*>(parent.internalPointer()) : root;
		Node* node = parentNode->child(row);
		if (node == 0) return false;
		ret = parentNode->removeChild(node);
		//Scene::freeNode(node);//do not clean up
		endRemoveRows();
	}
	return ret;
}

bool HierarchyTreeModel::insertRows(int row, int count, const QModelIndex& parent) {
	return false;
}
bool HierarchyTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) {
	if (action == Qt::IgnoreAction)
		return false;
	int targetRow = row == -1 ? rowCount(parent) : row;
	Node* node = *(Node**)(data->data(mimeTypes().front()).constData());

	int origRow = node->row();
	QModelIndex origParent = this->parent(createIndex(origRow, 0, node));

	if ((node->parent() == parent.internalPointer() || (node->parent() == root && parent.internalPointer() == 0))//is node's parent is target parent?
		&& origRow < row) row = row - 1;//and if node's row < target row then make target row -1 because we will remove node from parent

	Editor::ins().pushCommand(new ParentCommand(this, node, parent, row, origParent, origRow));

	beginRemoveRows(origParent, origRow, origRow + 1);
	node->detach();
	endRemoveRows();

	addNode(node, row, parent);

	markDropMimeDataRemove = true;
	return true;
}
